package com.yjhh.chdataservice.service;

import com.google.common.collect.Lists;
import com.yjhh.chdataservice.InitDataFactory;
import com.yjhh.chdataservice.beans.*;
import com.yjhh.chdataservice.component.CommonDataComponent;
import com.yjhh.chdataservice.component.ESClientManager;
import com.yjhh.chdataservice.except.YJHHException;
import com.yjhh.chdataservice.util.CommonResultData;
import com.yjhh.chdataservice.util.DataConsts;
import com.yjhh.chdataservice.util.DataTools;
import com.yjhh.chdataservice.util.XaUtil;
import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram;
import org.elasticsearch.search.aggregations.bucket.terms.*;
import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregator;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * 产业分布业务逻辑实现类
 */
@Service
@Log4j2
public class IndustryInfoServiceImpl implements IndustryInfoService {

    @Value("${dict.industry.dictid}")
    private String industryDictid;

    @Autowired
    private ESClientManager esClientManager;

    @Autowired
    private InitDataFactory initDataFactory;

    @Autowired
    private CommonDataComponent commonDataComponent;

    @Override
    public CommonResultData<List<TPGWPostInfoVo>> outOfPovertyPost(String areaCode) throws YJHHException {

        DeptBean sysDeptInfo = commonDataComponent.getSysDeptInfo(areaCode);
        if (sysDeptInfo == null) {
            return new CommonResultData<>(HttpStatus.OK.value(), "no data", null);
        }

        List<DeptBean> subDept = commonDataComponent.getSubDeptByDeptId(sysDeptInfo.getDeptID());

        List<TPGWPostInfoVo> tPGWPostInfoVos = new ArrayList<>();

        Map<String, String> map = new HashedMap();
        for (DeptBean deptBean : subDept) {
            map.put(deptBean.getDeptName(), deptBean.getDeptName());
        }

        getOutOfPovertyPostByCity(sysDeptInfo, tPGWPostInfoVos);

        //为了保证区县的顺序，以及无数据的区县也需要显示，所以需要如下操作
        List<TPGWPostInfoVo> resultCollect = subDept.parallelStream().map(deptBean -> {
            for (TPGWPostInfoVo tPGWPostInfo : tPGWPostInfoVos) {
                if (deptBean.getDeptName().equalsIgnoreCase(tPGWPostInfo.getAreaName())) {
                    return new TPGWPostInfoVo(tPGWPostInfo.getBq(), tPGWPostInfo.getGw(), deptBean.getAreaCode(), deptBean.getDeptName());
                }
            }
            return new TPGWPostInfoVo(0L, 0L, deptBean.getAreaCode(), deptBean.getDeptName());
        }).collect(Collectors.toList());

        return new CommonResultData<>(HttpStatus.OK.value(), "suc", resultCollect);
    }


    /**
     * 获取按城市 统计
     */
    private void getOutOfPovertyPostByCity(DeptBean sysDeptInfo, List<TPGWPostInfoVo> tPGWPostInfoVos) throws YJHHException {
        BoolQueryBuilder areacodequery = boolQuery().must(termQuery("a_deletestate", "0"));
        areacodequery.must(prefixQuery("a_deptno.keyword", sysDeptInfo.getDeptno()));
        SearchRequestBuilder searchRequestBuilder = esClientManager.getESClient().prepareSearch("pl_placementpoint_inf")
                .setTypes("placementpoint_inf").setSize(0).setQuery(areacodequery);

        TermsAggregationBuilder termsAgg = null;
        if (sysDeptInfo.getDeptLevel() == 2) {
            termsAgg = AggregationBuilders.terms("country").field("a_country.keyword")
                    .size(100);
        } else {
            termsAgg = AggregationBuilders.terms("city").field("a_city.keyword")
                    .size(100);
        }

        SumAggregationBuilder sumAggregationAllhs = AggregationBuilders.sum("allhs").field("b_point_placement_allhs");
        SumAggregationBuilder sumAggregationAlljob = AggregationBuilders.sum("alljob").field("b_point_contruction_alljob");

        termsAgg.subAggregation(sumAggregationAllhs);
        termsAgg.subAggregation(sumAggregationAlljob);
        searchRequestBuilder.addAggregation(termsAgg);

        log.info("request=" + searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        log.info("response=" + searchResponse.toString());


        StringTerms relocaAggregations = (StringTerms) searchResponse.getAggregations().asList().get(0);
        List<StringTerms.Bucket> buckets = relocaAggregations.getBuckets();

        for (StringTerms.Bucket bucket : buckets) {
            TPGWPostInfoVo tpgwPostInfoVo = new TPGWPostInfoVo();

            String key = bucket.getKeyAsString();
            long hs = Math.round(((Sum) bucket.getAggregations().asList().get(0)).getValue());
            long gw = Math.round(((Sum) bucket.getAggregations().asList().get(1)).getValue());
            tpgwPostInfoVo.setAreaName(key);
            tpgwPostInfoVo.setBq(hs);
            tpgwPostInfoVo.setGw(gw);
            tPGWPostInfoVos.add(tpgwPostInfoVo);
        }

        return;
    }

    @Override
    public CommonResultData<List<IndustryInfoStaticsVo>> getIndustryInfoStaticsByAreaCode(String areaCode) throws YJHHException {
        //1.获取areaCode所有子部门
        DeptBean sysDeptInfo = commonDataComponent.getSysDeptInfo(areaCode);
        if (sysDeptInfo == null) {
            return new CommonResultData<>(HttpStatus.OK.value(), "no data", null);
        }
        List<DeptBean> subDeptList = commonDataComponent.getSubDeptByDeptId(sysDeptInfo.getDeptID());

        List<String> subDicValues = commonDataComponent.getSubDicValuesByPId(industryDictid);

        List<IndustryInfoStaticsVo> industryInfoVos = new ArrayList<>();
        //转化数据格式为List<CommonNameValueVo<Long>>
        List<CommonNameValueVo<Long>> totalIndustryList = new ArrayList<>(subDicValues.parallelStream()
                .map(dictName -> new CommonNameValueVo<Long>(dictName, 0L))
                .collect(Collectors.toList()));

        for (DeptBean deptBean : subDeptList) {
            IndustryInfoStaticsVo industryInfoStaticsVo = new IndustryInfoStaticsVo();
            industryInfoStaticsVo.setParentAreaCode(sysDeptInfo.getAreaCode());
            industryInfoStaticsVo.setParentAreaLevel(sysDeptInfo.getAreaLevel());
            industryInfoStaticsVo.setParentAreaName(sysDeptInfo.getDeptName());

            industryInfoStaticsVo.setAreaCode(deptBean.getAreaCode());
            industryInfoStaticsVo.setAreaLevel(deptBean.getAreaLevel());
            industryInfoStaticsVo.setAreaName(deptBean.getDeptName());

            industryInfoStaticsVo.setIndustryList(subDicValues.parallelStream()
                    .map(dictName -> new CommonNameValueVo<Long>(dictName, 0L))
                    .collect(Collectors.toList()));

            industryInfoVos.add(industryInfoStaticsVo);
        }

        //2、通过聚合查询获取所有聚合后的区域和产业分类数量
        BoolQueryBuilder areacodequery = boolQuery().must(prefixQuery("deptno.keyword", sysDeptInfo.getDeptno()));
        SearchRequestBuilder searchRequestBuilder = esClientManager.getESClient().prepareSearch("proj_support_inf").setTypes("proj_support")
                .setSize(0);
        searchRequestBuilder.setQuery(areacodequery);

        TermsAggregationBuilder areaAgg = AggregationBuilders.terms("areaGroup").field(DataConsts.getPointDeptName(sysDeptInfo.getDeptLevel() + 1)).size(10000);
        TermsAggregationBuilder typeAgg = AggregationBuilders.terms("typeGroup").field("indusyrytype.keyword").size(100);
        areaAgg.subAggregation(typeAgg);

        searchRequestBuilder.addAggregation(areaAgg);

        System.out.println("request=" + searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        System.out.println("response=" + searchResponse.toString());

        StringTerms areaGroup = (StringTerms) searchResponse.getAggregations().asList().get(0);
        List<StringTerms.Bucket> areaGroupBuckets = areaGroup.getBuckets();

        for (StringTerms.Bucket bucket : areaGroupBuckets) {
            String areaName = bucket.getKeyAsString();
            Aggregation aggregation = bucket.getAggregations().asList().get(0);
            if (aggregation instanceof UnmappedTerms) {
                continue;
            }
            StringTerms typeGroup = (StringTerms) aggregation;
            List<StringTerms.Bucket> typeGroupBuckets = typeGroup.getBuckets();

            //给具体的产业赋值
            industryInfoVos.forEach(industryInfoVo -> {
                if (areaName.equalsIgnoreCase(industryInfoVo.getAreaName())) {
                    typeGroupBuckets.forEach(typeBuckets -> {
                        String indusyryType = typeBuckets.getKeyAsString();
                        long docCount = typeBuckets.getDocCount();
                        if (StringUtils.isNotBlank(indusyryType)) {
                            //由于示范产业类型有多选类型，所以需要拆分计算
                            String[] indusyryTypeArray = StringUtils.split(indusyryType, ",");
                            for(String indusyryTypeCode : indusyryTypeArray){
                                String indusyryTypeStr = commonDataComponent.getSysDicValueById(indusyryTypeCode);
                                List<CommonNameValueVo<Long>> industryList = industryInfoVo.getIndustryList();
                                industryList.forEach(industry -> {
                                    if (industry.getName().equalsIgnoreCase(indusyryTypeStr)) {
                                        industry.setValue(industry.getValue() + docCount);
                                    }
                                });
                                //合计值计算
                                totalIndustryList.forEach(industry -> {
                                    if (industry.getName().equalsIgnoreCase(indusyryTypeStr)) {
                                        industry.setValue(industry.getValue() + docCount);
                                    }
                                });
                            }
                        }
                    });
                }
            });
        }

        IndustryInfoStaticsVo industryInfoStaticsVo = new IndustryInfoStaticsVo();
        industryInfoStaticsVo.setAreaName("合计");
        industryInfoStaticsVo.setIndustryList(totalIndustryList);

        industryInfoVos.add(industryInfoStaticsVo);

        return new CommonResultData<>(HttpStatus.OK.value(), "suc", industryInfoVos);
    }

    @Override
    public CommonResultData<List<IndustryBaseInfoVo>> getIndustryInfoListByAreaCode(String areaCode) throws YJHHException {
        //1.获取areaCode所有子部门
        DeptBean sysDeptInfo = commonDataComponent.getSysDeptInfo(areaCode);
        if (sysDeptInfo == null) {
            return new CommonResultData<>(HttpStatus.OK.value(), "no data", null);
        }
        BoolQueryBuilder areacodequery = boolQuery().must(prefixQuery("deptno.keyword", sysDeptInfo.getDeptno()));
        SearchRequestBuilder searchRequestBuilder = esClientManager.getESClient().prepareSearch("proj_support_inf").setTypes("proj_support")
                .setSize(10000);
        searchRequestBuilder.setQuery(areacodequery);

        System.out.println("request=" + searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        System.out.println("response=" + searchResponse.toString());

        SearchHit[] searchHits = searchResponse.getHits().getHits();

        List<IndustryBaseInfoVo> list = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            Map<String, Object> searchHitSource = searchHit.getSource();
            list.add(new IndustryBaseInfoVo(DataTools.convertToStr(searchHitSource.get("supportid")),
                    DataTools.convertToStr(searchHitSource.get("industryname")),
                    commonDataComponent.getSysDicValueById(DataTools.convertToStr(searchHitSource.get("indusyrytype"))),
                    DataTools.convertToLone(searchHitSource.get("postcount")),
                    DataTools.convertToLone(searchHitSource.get("monthmoney")),
                    StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("pointx"))) ? 0.0 : Double
                            .parseDouble
                                    (DataTools.convertToStr(searchHitSource.get("pointx"))),
                    StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("pointy"))) ? 0.0 : Double
                            .parseDouble
                                    (DataTools.convertToStr(searchHitSource.get("pointy"))),
                    StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("b_pointx"))) ? 0.0 : Double
                            .parseDouble
                                    (DataTools.convertToStr(searchHitSource.get("b_pointx"))),
                    StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("b_pointy"))) ? 0.0 : Double
                            .parseDouble
                                    (DataTools.convertToStr(searchHitSource.get("b_pointy")))
            ));
        }

        return new CommonResultData<>(HttpStatus.OK.value(), "suc", list);
    }

    @Override
    public CommonResultData<IndustryInfoVo> getIndustryInfo(String industryId) throws YJHHException {
        QueryBuilder idsQueryBuilder = QueryBuilders.idsQuery().addIds(industryId);
        SearchRequestBuilder searchRequestBuilder = esClientManager.getESClient().prepareSearch("proj_support_inf").setTypes("proj_support")
                .setQuery(idsQueryBuilder);

        log.info("reqeust: " + searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        log.info("response:" + searchResponse.toString());

        SearchHit[] hits = searchResponse.getHits().getHits();
        if (hits == null || hits.length <= 0) {
            new CommonResultData<>(HttpStatus.OK.value(), "suc", null);
        }

        Map<String, Object> searchHitSource = hits[0].getSource();
        IndustryInfoVo industryInfoVo = new IndustryInfoVo(DataTools.convertToStr(searchHitSource.get("supportid")),
                DataTools.convertToStr(searchHitSource.get("industryname")),
                commonDataComponent.getSysDicValueById(DataTools.convertToStr(searchHitSource.get("indusyrytype"))),
                DataTools.convertToLone(searchHitSource.get("postcount")),
                DataTools.convertToLone(searchHitSource.get("monthmoney")),
                StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("pointx"))) ? 0.0 : Double
                        .parseDouble
                                (DataTools.convertToStr(searchHitSource.get("pointx"))),
                StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("pointy"))) ? 0.0 : Double
                        .parseDouble
                                (DataTools.convertToStr(searchHitSource.get("pointy"))),
                StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("b_pointx"))) ? 0.0 : Double
                        .parseDouble
                                (DataTools.convertToStr(searchHitSource.get("b_pointx"))),
                StringUtils.isBlank(DataTools.convertToStr(searchHitSource.get("b_pointy"))) ? 0.0 : Double
                        .parseDouble
                                (DataTools.convertToStr(searchHitSource.get("b_pointy")))
        );

        industryInfoVo.setPlannumber(DataTools.convertToStr(searchHitSource.get("plannumber")));
        industryInfoVo.setConphase(DataTools.convertToStr(searchHitSource.get("conphase")));
        industryInfoVo.setOperationstage(DataTools.convertToStr(searchHitSource.get("operationstage")));
        industryInfoVo.setIndustryname(DataTools.convertToStr(searchHitSource.get("industryname")));
        industryInfoVo.setPointdistance(DataTools.convertToStr(searchHitSource.get("pointdistance")));
        industryInfoVo.setIndustryschedule(DataTools.convertToStr(searchHitSource.get("industryschedule")));
        industryInfoVo.setSupportintroduce(DataTools.convertToStr(searchHitSource.get("supportintroduce")));
        industryInfoVo.setPointpostcount(DataTools.convertToStr(searchHitSource.get("pointpostcount")));
        industryInfoVo.setOther(DataTools.convertToStr(searchHitSource.get("other")));
        industryInfoVo.setProjname(DataTools.convertToStr(searchHitSource.get("projname")));

        return new CommonResultData<>(HttpStatus.OK.value(), "suc", industryInfoVo);
    }

    @Override
    public CommonResultData<List<CommonNameValueVo<Long>>> getAvgMonthMoneyByAreaCode(String areaCode) throws YJHHException {
        //1.获取areaCode所有子部门
        DeptBean sysDeptInfo = commonDataComponent.getSysDeptInfo(areaCode);
        if (sysDeptInfo == null) {
            return new CommonResultData<>(HttpStatus.OK.value(), "no data", null);
        }
        List<DeptBean> subDeptList = commonDataComponent.getSubDeptByDeptId(sysDeptInfo.getDeptID());

        List<CommonNameValueVo<Long>> deptDataList = subDeptList.parallelStream().map(deptBean -> {
            return new CommonNameValueVo<Long>(deptBean.getDeptName(), 0L);
        }).collect(Collectors.toList());

        BoolQueryBuilder areacodequery = boolQuery().must(prefixQuery("deptno.keyword", sysDeptInfo.getDeptno()));
        SearchRequestBuilder searchRequestBuilder = esClientManager.getESClient().prepareSearch("proj_support_inf").setTypes("proj_support")
                .setSize(0);
        searchRequestBuilder.setQuery(areacodequery);

        TermsAggregationBuilder areaAgg = AggregationBuilders.terms("areaGroup").field(DataConsts.getPointDeptName(sysDeptInfo.getDeptLevel() + 1)).size(10000);
        AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg("avgMoney").field("monthmoney");
        areaAgg.subAggregation(avgAggregationBuilder);

        searchRequestBuilder.addAggregation(areaAgg);

        System.out.println("request=" + searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        System.out.println("response=" + searchResponse.toString());

        Aggregation aggregation = searchResponse.getAggregations().asList().get(0);
        if (aggregation instanceof UnmappedTerms) {
            return new CommonResultData<>(HttpStatus.OK.value(), "no data", deptDataList);
        }

        StringTerms areaGroup = (StringTerms) aggregation;
        List<StringTerms.Bucket> areaGroupBuckets = areaGroup.getBuckets();

        for (StringTerms.Bucket bucket : areaGroupBuckets) {
            String areaName = bucket.getKeyAsString();
            InternalAvg internalAvg = (InternalAvg)bucket.getAggregations().asList().get(0);
            double avgValue = internalAvg.getValue();
            deptDataList.forEach(commonVo -> {
                if (commonVo.getName().equalsIgnoreCase(areaName)){
                    commonVo.setValue(new BigDecimal(avgValue).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                }
            });
        }

        return  new CommonResultData(HttpStatus.OK.value(), "suc", deptDataList);
    }

    @Override
    public CommonResultData<List<CommonNameValueVo<Long>>> getIndustryStaticsByAreaCode(String areaCode) throws YJHHException {
        DeptBean sysDeptInfo = commonDataComponent.getSysDeptInfo(areaCode);
        if (sysDeptInfo == null) {
            return new CommonResultData<>(HttpStatus.OK.value(), "no data", null);
        }

        List<String> subDicValues = commonDataComponent.getSubDicValuesByPId(industryDictid);

        List<IndustryInfoStaticsVo> industryInfoVos = new ArrayList<>();
        //转化数据格式为List<CommonNameValueVo<Long>>
        List<CommonNameValueVo<Long>> industryCountList = new ArrayList<>(subDicValues.parallelStream()
                .map(dictName -> new CommonNameValueVo<Long>(dictName, 0L))
                .collect(Collectors.toList()));

        BoolQueryBuilder areacodequery = boolQuery().must(prefixQuery("deptno.keyword", sysDeptInfo.getDeptno()));
        SearchRequestBuilder searchRequestBuilder = esClientManager.getESClient().prepareSearch("proj_support_inf").setTypes("proj_support")
                .setSize(0);
        searchRequestBuilder.setQuery(areacodequery);

        TermsAggregationBuilder industryTypeAgg = AggregationBuilders.terms("industryGroup").field("indusyrytype.keyword").size(10000);
        searchRequestBuilder.addAggregation(industryTypeAgg);

        System.out.println("request=" + searchRequestBuilder.toString());
        SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
        System.out.println("response=" + searchResponse.toString());

        StringTerms industryTypeGroup = (StringTerms) searchResponse.getAggregations().asList().get(0);
        List<StringTerms.Bucket> areaGroupBuckets = industryTypeGroup.getBuckets();

        for (StringTerms.Bucket bucket : areaGroupBuckets) {
            String industryTypeCode = bucket.getKeyAsString();
            long industryCount = bucket.getDocCount();
            if(StringUtils.isNotBlank(industryTypeCode)){
                String[] industryTypeCodeArray = StringUtils.split(industryTypeCode, ",");
                for(String industryType : industryTypeCodeArray) {
                    String indusyryTypeStr = commonDataComponent.getSysDicValueById(industryType);
                    industryCountList.forEach(commonNameValueVo -> {
                        if (StringUtils.equalsIgnoreCase(indusyryTypeStr,commonNameValueVo.getName())){
                            commonNameValueVo.setValue(commonNameValueVo.getValue() + industryCount);
                        }
                    });
                }
            }
        }

        return  new CommonResultData(HttpStatus.OK.value(), "suc", industryCountList);
    }
}
